#pragma once
#include <string>
#include <iosfwd>

class CMediaTypes;

namespace MkvParser
{

class Track;
class Block;
class Cluster;

class Stream
{
    Stream(const Stream&);
    Stream& operator=(const Stream&);

public:
    virtual ~Stream();
    void Init();
    
    std::wstring GetId() const;  //IPin::QueryId
    std::wstring GetName() const;  //IPin::QueryPinInfo
    virtual void GetMediaTypes(CMediaTypes&) const = 0;
    virtual HRESULT QueryAccept(const AM_MEDIA_TYPE*) const = 0;
    virtual HRESULT UpdateAllocatorProperties(ALLOCATOR_PROPERTIES&) const = 0;

#if 0  //TODO: use this for incremental loading
    virtual HRESULT PopulateSample(IMediaSample*, __int64&) = 0;
#endif

    virtual long GetBufferSize() const = 0;
    HRESULT PopulateSample(IMediaSample*);    

    __int64 GetDuration() const;
    __int64 GetCurrPosition() const;
    __int64 GetStopPosition() const;
    __int64 GetCurrTime() const;
    __int64 GetStopTime() const;

    HRESULT GetAvailable(LONGLONG*) const;

    //NOTE: too inefficient
    //void LoadCurrPosition(LONGLONG, DWORD, __int64& parse_result);
    
    const Cluster* SetCurrPosition(LONGLONG currTime, DWORD dwCurr);
    void SetCurrPosition(const Cluster*);

    void SetStopPosition(LONGLONG, DWORD);
    void SetStopPositionEOS();
    
    ULONG GetClusterCount() const;
    
    template<typename T, typename S, typename F>
    struct TCreateOutpins
    {
        F* f;
        
        typedef S* (*pfn_t)(T*);
        pfn_t pfn;
        
        TCreateOutpins(F* f_, pfn_t pfn_) : f(f_), pfn(pfn_) {}

        void operator()(T* t) const
        {
            if (S* s = (*pfn)(t))
                f->CreateOutpin(s);
        }
    };

protected:
    explicit Stream(Track*);    
    Track* const m_pTrack;
    bool m_bDiscontinuity;
    const Block* m_pCurr;
    const Block* m_pStop;
    //LONGLONG m_baseTime;  //absolute, and scaled
    const Cluster* m_pBase;

    virtual std::wostream& GetKind(std::wostream&) const = 0;
    virtual HRESULT OnPopulateSample(const Block* pNext, IMediaSample* pSample) const = 0;

};

}  //end namespace MkvParser
